#pragma once
#include <unordered_map>
#include <memory>
#include "Comman.hpp"
#include "Epoller.hpp"
#include "Connection.hpp"

// 类似一个任务容器,①管理connection和内核事件②事件派发
class Reactor
{
    static const int gnum = 64;

public:
    Reactor()
    {
        _epoller = std::make_unique<Epoller>();
    }
    void AddConnection(int fd, uint32_t event, InetAddr addr,int type)
    {
        // 1.构建connection
        Connection *conn = new Connection(fd);
        conn->SetEvent(event);
        conn->SetType(type);
        conn->SetAddr(addr);
        //将该conn指向该reactor
        conn->SetReactor(this);
        //根据类型注册方法
        if(conn->Type() == ListenerType)
        {
           conn->RegisterHandler(_OnAccept,nullptr,nullptr);
        }
        else
        {
            conn->RegisterHandler(_OnRead,_OnWrite,_OnExcepter);
        }
        // // 1.1初始化改连接所对应的方法
        // conn->RegisterHandler(recver, sender, excepter);
        // 2.打透到内核epoll
        if (!_epoller->AddEvent(conn->Sockfd(), conn->Event()))
            return;
        // 3.添加到map
        _connections.insert(std::make_pair(fd, conn));
    }
    void LoopOnce(int timeout)
    {
        // int cal = 0;
        // 得知道哪fd事件就绪,等待...
        //我的浏览器，一次发送两个请求，但只通知一次
        int n = _epoller->Wait(revents, gnum, timeout);
       // LOG(DEBUG, "n = %d", n);
        // 处理就绪事件
        for (int i = 0; i < n; i++)
        {
            int sockfd = revents[i].data.fd;
            uint32_t event = revents[i].events;
            if (event & EPOLLERR || event & EPOLLHUP)
                event |= (EPOLLIN | EPOLLOUT); // 异常事件，需要关注可读可写
            // 交给上层处理事件,相应的连接处理对应的方法
            if (IsExitConnection(sockfd) && (event & EPOLLIN))
            {
                //每个回调函数需要传入connection参数的原因是需要connection再次调用reactor里的AddConnection
                _connections[sockfd]->_handler_recever(_connections[sockfd]);
            }
            if (IsExitConnection(sockfd) && (event & EPOLLOUT))
            {
                _connections[sockfd]->_handler_sender(_connections[sockfd]);
            }
        }
        // LOG(DEBUG,"cal = %d",cal);
        // cal++;
    }
    //修改关心的事件
    void EnableConnectionReadWritr(int fd,bool read,bool write)
    {
        if(!IsExitConnection(fd))
        {
            return;
        }
        uint32_t event = (read ? EPOLLIN : 0) | (write ? EPOLLOUT : 0) | EPOLLET;
        //修改事件
        _connections[fd]->SetEvent(event);
        //维护到epoll
        _epoller->ModifyEvent(fd,event);
    }
    //移除连接
    void RemoveConnection(int fd)
    {
        if(!IsExitConnection(fd))
        {
            return;
        }
        //从epoll移除
        _epoller->RemoveEvent(fd);
        _connections[fd]->Close();

        //从map移除
        delete _connections[fd];
        _connections.erase(fd);
        //关闭文件描述符
    }
    void Dispatch()
    {
        //不断检测是否有任务就绪
        int timeout = -1;
        _isrunning = true;
        while (_isrunning)
        {
            LoopOnce(timeout);
            //LOG(DEBUG,"当前连接列表:%s",PrintList().c_str());
        }
        LOG(DEBUG, "TcpServer exit");
        _isrunning = false;
    }
    bool IsExitConnection(int sockfd)
    {
        return _connections.find(sockfd) != _connections.end();
    }
    void SetListenHandler(handler_t accept)
    {
        _OnAccept = accept;
    }
    void SetNormalHandler(handler_t read, handler_t write, handler_t excepter)
    {
        _OnRead = read;
        _OnWrite = write;
        _OnExcepter = excepter;
    }
    std::string PrintList()
    {
        std::string str;
        for(auto &conn : _connections)
        {
            str += std::to_string(conn.second->Sockfd()) + " ";
        }
        return str;
    }
    ~Reactor() {}

private:
    std::unordered_map<int, Connection *> _connections;
    std::unique_ptr<Multiplex> _epoller;
    bool _isrunning;
    struct epoll_event revents[gnum]; // 捞取就绪事件
public:
    //就绪事件处理方法集
    handler_t _OnAccept;
    handler_t _OnRead;
    handler_t _OnWrite;
    handler_t _OnExcepter;
};
